package com.ruoyi.common.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerBuilder;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import org.springframework.cache.support.NullValue;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;

/**
 * 通过jackjson框架进行json转化
 *
 * @author hcx
 */
public class JsonUtils {
    private static final ObjectMapper MAPPER;

    static {
        //创建ObjectMapper对象
        MAPPER = build();
    }

    public static ObjectMapper getMapper() {
        return MAPPER;
    }

    private static ObjectMapper build() {
        //创建ObjectMapper对象
        ObjectMapper mapper = new ObjectMapper();

        //configure方法 配置一些需要的参数
        // 转换为格式化的json 显示出来的格式美化（不建议开启会多占用存储空间）
//        MAPPER.enable(SerializationFeature.INDENT_OUTPUT);

        //序列化的时候序列对象的那些属性
        //JsonInclude.Include.NON_DEFAULT 属性为默认值不序列化
        //JsonInclude.Include.ALWAYS      所有属性
        //JsonInclude.Include.NON_EMPTY   属性为 空（“”） 或者为 NULL 都不序列化
        //JsonInclude.Include.NON_NULL    属性为NULL 不序列化
        mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);


        //反序列化时,遇到未知属性会不会报错
        //true - 遇到没有的属性就报错 false - 没有的属性不会管，不会报错
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        //如果是空对象的时候,不抛异常
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

        // 忽略 transient 修饰的属性
        mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);

        //修改序列化后日期格式
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

        //处理不同的时区偏移格式
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
//        MAPPER.registerModule(new JavaTimeModule());
        return mapper;
    }

    /**
     * 序列化对象成json字符串
     * @param object 数据
     * @return json字符串
     */
    public static String toJson(Object object)
    {
        try {
            return object == null ? null : MAPPER.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * json字符串转对象
     * @param json json字符串
     * @return 对象
     * @param <T> 对象类型
     */
    public static <T> T formJson(String json,TypeReference<T> typeReference)
    {
        try {
            return json == null ? null : MAPPER.readValue(json, typeReference);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Json字符串反序列化对象
     * @param json json字符串
     * @param tClass class
     * @return 结果
     */
    public static <T> T formJson(String json,Class<T> tClass)
    {
        try {
            return json == null ? null : MAPPER.readValue(json, tClass);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * json字符串转成集合对象
     * @param json json字符
     * @param eClass 集合泛型类
     * @return 结果
     * @param <T> 泛型接受避免传递参数
     */
    public static <T> T formJsonList(String json, Class<?> eClass){
        try {
            return json == null ? null : MAPPER.readValue(json, MAPPER.getTypeFactory().constructCollectionType(List.class, eClass));
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * json字符串转成map对象
     * @param json json字符
     * @param keyClass key 类型
     * @param valueClass value 类型
     * @return 结果
     * @param <T> 泛型接受
     */
    public static <T> T formJsonMap(String json, Class<?> keyClass, Class<?> valueClass){
        try {
            return json == null ? null : MAPPER.readValue(json, MAPPER.getTypeFactory().constructMapType(Map.class, keyClass, valueClass));
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 该类只是在JackJson序列化的时候过滤掉指定属性值，所有只有一个toJson的序列化方法
     */
    public static class JsonSimpleBeanPropertyFilter {
        private static final ObjectMapper MAPPER_SIMPLE;
        static {
            MAPPER_SIMPLE = MAPPER.copy();
            SimpleModule module = new SimpleModule();
            module.setSerializerModifier(new SerializerModifier());
            MAPPER_SIMPLE.registerModule(module);
        }

        public static String toJson(Object object,String... propertyArray) {
            try {
                SimpleFilterProvider simpleFilterProvider = new SimpleFilterProvider()
                        .addFilter(SerializerModifier.FILTER_ID, SimpleBeanPropertyFilter.serializeAllExcept(propertyArray));
                return MAPPER_SIMPLE.writer(simpleFilterProvider).writeValueAsString(object);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }

        private static class SerializerModifier extends BeanSerializerModifier {
            public static final String FILTER_ID = "SimpleBeanPropertyFilter";
            @Override
            public BeanSerializerBuilder updateBuilder(SerializationConfig config, BeanDescription beanDesc, BeanSerializerBuilder builder) {
                builder.setFilterId(FILTER_ID);
                return super.updateBuilder(config, beanDesc, builder);
            }
        }
    }

    /**
     * 该类下的toJson方法会写入类的信息，方便formJson准确反序列
     */
    public static class ClassAutoload {
        private static final ObjectMapper MAPPER_CLASS_AUTOLOAD;
        static {
            MAPPER_CLASS_AUTOLOAD = MAPPER.copy();
            MAPPER_CLASS_AUTOLOAD.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
            MAPPER_CLASS_AUTOLOAD.registerModule((new SimpleModule()).addSerializer(new NullValueSerializer(null)));
        }

        public static String toJson(Object object) {
            try {
                return object == null ? null : MAPPER_CLASS_AUTOLOAD.writeValueAsString(object);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }

        public static <T> T formJson(String json, Class<T> tClass) {
            try {
                return json == null ? null : MAPPER_CLASS_AUTOLOAD.readValue(json, tClass);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }

        private static class NullValueSerializer extends StdSerializer<NullValue> {
            private final String classIdentifier;

            NullValueSerializer(@Nullable String classIdentifier) {
                super(NullValue.class);
                this.classIdentifier = StringUtils.hasText(classIdentifier) ? classIdentifier : "@class";
            }

            @Override
            public void serialize(NullValue value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
                jgen.writeStartObject();
                jgen.writeStringField(this.classIdentifier, NullValue.class.getName());
                jgen.writeEndObject();
            }
        }
    }
}
